package com.study.jdk8.stream;


import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @version V1.0
 * @title: Test
 * @description: ${DESCRIPTION}
 * @author: wanghuilong
 * @date: 2019-08-02 15:59
 * @copyright: http://fingo.com.my/
 */
public class Test {

    public static void main(String[] args) {
        Stream<String> stream = Stream.of("a", "b", "c");
        stream.map(String::toUpperCase).collect(Collectors.toList())
                .forEach(System.out::println);
        Arrays.asList(1, 2, 3, 4).stream().map(n -> n * n + ",").collect(Collectors.toList())
                .forEach(System.out::print);

        Stream<List<Integer>> listStream = Stream.of(
                Arrays.asList(1, 2, 3, 4),
                Arrays.asList(5, 6, 7, 8),
                Arrays.asList(9, 10, 11, 12)
        );
        Object str[] = listStream.flatMap((childList) -> childList.stream()).toArray();
        System.out.println(Arrays.toString(str));

        Integer[] sixNums = {1, 2, 3, 4, 5, 6};
        Integer[] evens = Stream.of(sixNums).filter(n -> n % 2 == 0).toArray(Integer[]::new);
        System.out.println(Arrays.toString(evens));

        Stream.of(sixNums).filter(n -> n * 2 > 0).forEach(n -> {
            n += 1;
            System.out.println(n);
        });

        String strA = "abcd", strB = null;
        print(strA);
        print("");
        getLength(strA);
        getLength("");
        getLength(strB);

        String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
        System.out.println(concat);
        Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);

        List<Person> persons = testLimitAndSkip();
        List<String> personList = persons.stream().map(Person::getName).limit(10).collect(Collectors.toList());
        System.out.println(personList);

        persons = new ArrayList();
        for (int i = 1; i <= 5; i++) {
            Person person = new Person(i, "name" + i);
            persons.add(person);
        }

        System.out.println("----limit/skip----");

        List<Person> personList2 = persons.stream().sorted((p1, p2) -> {
            System.out.println(p1.getName());
            return p1.getName().compareTo(p2.getName());
        }).limit(2).collect(Collectors.toList());
        System.out.println(Arrays.toString(personList2.toArray()));

        persons = new ArrayList();
        persons.add(new Person(1, "name" + 1, 10));
        persons.add(new Person(2, "name" + 2, 21));
        persons.add(new Person(3, "name" + 3, 34));
        persons.add(new Person(4, "name" + 4, 6));
        persons.add(new Person(5, "name" + 5, 55));

        boolean isAllAdult = persons.stream().allMatch(p -> p.getAge() > 18);
        System.out.println("All are adult? " + isAllAdult);
        boolean isThereAnyChild = persons.stream().anyMatch(p -> p.getAge() < 12);
        System.out.println("Any child? " + isThereAnyChild);

        Random seed = new Random();
        Supplier<Integer> random = seed::nextInt;
        Stream.generate(random).limit(10).forEach(System.out::println);

        IntStream.generate(() -> (int) (System.nanoTime() % 100)).limit(10).forEach(System.out::println);

        Stream.generate(new PersonSupplier()).limit(10)
                .forEach(p -> System.out.println(p.getName() + ", " + p.getAge()));

        Stream.iterate(0, n -> n + 3).limit(10).forEach(x -> System.out.print(x + " "));

        Map<Integer, List<Person>> personGroups = Stream.generate(new PersonSupplier())
                .limit(100)
                .collect(Collectors.groupingBy(Person::getAge));
        Iterator<Map.Entry<Integer, List<Person>>> iterator = personGroups.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Integer, List<Person>> personsList = iterator.next();
            System.out.println("Age " + personsList.getKey() + " = " + personsList.getValue().size());
        }
        Map<Boolean, List<Person>> children = Stream.generate(new PersonSupplier())
                .limit(100)
                .collect(Collectors.groupingBy(p -> p.getAge() < 18));
        System.out.println("Children number: " + children.get(true).size());
        System.out.println("Adult number: " + children.get(false).size());
    }

    private static class PersonSupplier implements Supplier<Person> {
        private int index = 0;
        private Random random = new Random();

        @Override
        public Person get() {
            return new Person(index++, "StormTestUser" + index, random.nextInt(100));
        }
    }

    public static List<Person> testLimitAndSkip() {
        List<Person> persons = new ArrayList();
        for (int i = 1; i <= 10000; i++) {
            Person person = new Person(i, "name" + i);
            persons.add(person);
        }
        return persons;
    }

    private static class Person {
        public int no;
        private String name;
        private Integer age;

        public String getName() {
            System.out.println(name);
            return name;
        }

        public Person(int no, String name) {
            this.no = no;
            this.name = name;
        }

        public Person(int no, String name, Integer age) {
            this.no = no;
            this.name = name;
            this.age = age;
        }

        public Integer getAge() {
            return age;
        }
    }

    public static void print(String text) {
        Optional.ofNullable(text).ifPresent(System.out::println);
        if (text != null) {
            System.out.println(text);
        }
    }

    public static int getLength(String text) {
        return Optional.ofNullable(text).map(String::length).orElse(-1);
    }
}
